﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CartItemServiceTests.cs" company="DST Nexdox">
//   Copyright (c) DST Nexdox. All rights reserved.
// </copyright>
// <summary>
//   Defines the CartItemServiceTests type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ServiceTests
{
  using System;
  using System.Collections.Generic;
  using System.ComponentModel.Design;

  using BusinessEngineInterfaces;
  using Entities;
  using Exceptions;
  using FluentAssertions;
  using Moq;
  using NUnit.Framework;
  using ServiceInterfaces;
  using Services;
  using UnityRepository.Interfaces;

  [TestFixture]
  public class CartItemServiceTests
  {
    private Mock<ICartItemEngine> cartItemEngine;
    private Mock<ICartItemRepository> cartItemRepository;
    private Mock<ICheckOutRepository> checkOutRepository;
    private Mock<IDocumentRepository> documentRepository;
    private ICartItemService cartItemService;

    [SetUp]
    public void SetUp()
    {
      this.cartItemEngine = new Mock<ICartItemEngine>();
      this.cartItemRepository = new Mock<ICartItemRepository>();
      this.checkOutRepository = new Mock<ICheckOutRepository>();
      this.documentRepository = new Mock<IDocumentRepository>();

      this.cartItemService = new CartItemService(
        this.cartItemEngine.Object,
        this.cartItemRepository.Object,
        this.checkOutRepository.Object,
        this.documentRepository.Object);
    }

    [Test]
    public void GivenValidData_WhenDocumentsAreAddedToACart_ThenTheCartIsUpdated()
    {
      this.cartItemService.AddItems(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<IEnumerable<String>>());

      this.cartItemEngine.Verify(
        e => e.AddItems(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<IEnumerable<String>>()),
        Times.Once);
    }

    [Test]
    public void GivenACartId_WhenIAskToGetTotalNumberOfCartItems_IGetACountOFTheNumberOfCartItems()
    {
      this.cartItemService.GetNumberOfItemsInCart(It.IsAny<String>());

      this.cartItemRepository.Verify(s => s.GetNumberOfItemsInCart(It.IsAny<String>()), Times.Once());
    }

    [Test]
    public void GivenACartId_WhenIAskToGetTotalNumberOfCartItems_AndTheDatabaseIsUnavailable_IGetACountOFTheNumberOfCartItems()
    {
      this.cartItemRepository.Setup(c => c.GetNumberOfItemsInCart(It.IsAny<String>())).Throws<Exception>();

      Action act = () => this.cartItemService.GetNumberOfItemsInCart(It.IsAny<String>());

      act.ShouldThrow<UnityException>();
    }

    [Test]
    public void GivenACartId_WhenIAskToGetAllItemsInTheCart_IGetAllItemsInTheCart()
    {
      this.cartItemService.GetCart(It.IsAny<String>());

      this.cartItemRepository.Verify(s => s.GetCart(It.IsAny<String>()), Times.Once());
    }

    [Test]
    public void GivenACartId_WhenIAskToGetAllItemsInTheCart_AndTheDatabaseIsUnavailable_IGetAllItemsInTheCart()
    {
      this.cartItemRepository.Setup(c => c.GetCart(It.IsAny<String>())).Throws<Exception>();

      Action act = () => this.cartItemService.GetCart(It.IsAny<String>());

      act.ShouldThrow<UnityException>();
    }

    [Test]
    public void WhenACartItemIsDeleted_AndItIsFound_ThenItIsDeleted()
    {
      this.cartItemRepository.Setup(m => m.GetCart(It.IsAny<String>(), It.IsAny<String>()))
        .Returns(new CartItem { Document = new Document { CheckOut = new CheckOut() } });

      this.checkOutRepository.Setup(m => m.GetCheckOut(It.IsAny<String>())).Returns(new CheckOut());

      this.cartItemService.RemoveItem(It.IsAny<String>(), It.IsAny<String>());

      Assert.True(true, "No exceptions thrown");
      this.cartItemRepository.Verify(s => s.Delete(It.IsAny<CartItem>()), Times.Once());
      this.checkOutRepository.Verify(s => s.Delete(It.IsAny<CheckOut>()), Times.Once());
    }

    [Test]
    public void WhenACartItemIsDeleted_AndTheDatabaseIsNotAvailable_ThenAnUnityExceptionIsThrown()
    {
      this.cartItemRepository.Setup(m => m.GetCart(It.IsAny<String>(), It.IsAny<String>())).Throws<Exception>();
      Assert.Throws<UnityException>(() => this.cartItemService.RemoveItem(It.IsAny<String>(), It.IsAny<String>()));
    }

    [Test]
    public void WhenCartItemIsDeleted_AndTheDatabaseIsNotAvailable_ThenAnUnityExceptionIsThrown()
    {
      this.cartItemRepository.Setup(m => m.GetCart(It.IsAny<String>(), It.IsAny<String>())).Returns(new CartItem());
      this.cartItemRepository.Setup(m => m.Delete(It.IsAny<CartItem>())).Throws<Exception>();
      Assert.Throws<UnityException>(() => this.cartItemService.RemoveItem(It.IsAny<String>(), It.IsAny<String>()));
    }

    [Test]
    public void GivenAValidBasket_WhenIAskToClearTheBasket_TheBasketIsCleared()
    {
      this.cartItemRepository.Setup(p => p.GetCart(It.IsAny<String>()))
                         .Returns(new List<CartItem>
                           {
                             new CartItem { Id = 1, Document = new Document() },
                             new CartItem { Id = 2, Document = new Document() },
                             new CartItem { Id = 3, Document = new Document() }
                           });

      this.cartItemService.ClearCart(It.IsAny<String>());

      this.cartItemRepository.Verify(c => c.Delete(It.IsAny<IEnumerable<CartItem>>()), Times.Exactly(1));
      this.checkOutRepository.Verify(c => c.Delete(It.IsAny<IEnumerable<CheckOut>>()), Times.Exactly(1));
    }

    [Test]
    public void GivenAValidBasket_WhenIAskToClearTheBasket_AndTheDatabaseIsNotAvailable_ThenAnUnityExceptionIsThrown()
    {
      this.cartItemRepository.Setup(cir => cir.GetCart(It.IsAny<String>())).Throws<Exception>();
      this.checkOutRepository.Setup(cor => cor.GetCheckOutsForCart(It.IsAny<String>())).Throws<Exception>();

      Assert.Throws<UnityException>(() => this.cartItemService.ClearCart(It.IsAny<String>()));
    }

    [Test]
    public void GivenAValidBasket_WhenIAskForTheCartAsPagedResult_IGetThatPageOfItems()
    {
      PagedResult<CartItem> result = this.cartItemService.GetCartItems("cartId", 1, 10);
      this.cartItemRepository.Verify(cir => cir.GetCart(It.IsAny<String>(), It.IsAny<Int32>(), It.IsAny<Int32>()), Times.Once);
    }

    [Test]
    public void GivenAValidBasket_WhenIAskForTheCartAsPagedResult_AndTheDatabaseIsNotAvailable_ThenAnUnityExceptionIsThrown()
    {
      this.cartItemRepository.Setup(m => m.GetCart(It.IsAny<String>(), It.IsAny<Int32>(), It.IsAny<Int32>())).Throws<Exception>();
      Assert.Throws<UnityException>(() => this.cartItemService.GetCartItems("cartId", 1, 10));
    }
  }
}
